package com.camus.verify.biz.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import com.camus.utils.SpecificationUtil;
import com.camus.verify.biz.MatchBiz;
import com.camus.verify.biz.VerifyTaskBiz;
import com.camus.verify.bo.SpecWithPrice;
import com.camus.verify.bo.SpecWithPriceHelper;
import com.camus.verify.entity.VerifyTask;
import com.camus.verify.entity.VerifyTaskAp;
import com.camus.verify.entity.VerifyTaskInvoice;
import com.camus.verify.enums.VerifyTaskStatusEnum;
import com.camus.verify.service.IVerifyTaskApService;
import com.camus.verify.service.IVerifyTaskInvoiceService;
import com.camus.verify.service.IVerifyTaskService;
import com.camus.verify.vo.VerifyTaskApVO;
import com.camus.verify.vo.VerifyTaskInvoiceVO;
import com.google.common.collect.Lists;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;

@Service
public class VerifyTaskBizImpl implements VerifyTaskBiz {

	private static final Logger log = LoggerFactory.getLogger(VerifyTaskBizImpl.class);

	@Value("${priceTolerance:0.05}")
	private BigDecimal priceTolerance;
	@Autowired
	private IVerifyTaskService verifyTaskService;
	@Autowired
	private IVerifyTaskInvoiceService taskInvoiceService;
	@Autowired
	private IVerifyTaskApService taskApService;
	@Autowired
	private MatchBiz matchBiz;
	@Autowired
	private TransactionTemplate transactionTemplate;
	
	@Override
	public VerifyTask submitVerifyTask(List<VerifyTaskInvoiceVO> invoiceList, List<VerifyTaskApVO> apgList) {
		// 生成核销任务编号
		String code = "Task" + IdUtil.getSnowflake().nextIdStr();
		VerifyTask task = genVerifyTask(code, invoiceList, apgList);
		List<VerifyTaskInvoice> taskInvoiceList = genVerifyTaskInvoiceList(task, invoiceList);
		List<VerifyTaskAp> taskApList = genVerifyTaskApList(task, apgList);

		// 保存核销任务主表和两个明细表
		transactionTemplate.executeWithoutResult(status -> {
			verifyTaskService.save(task);
			taskInvoiceService.saveBatch(taskInvoiceList);
			taskApService.saveBatch(taskApList);
		});
		
		return task;
	}

	private List<VerifyTaskAp> genVerifyTaskApList(VerifyTask task, List<VerifyTaskApVO> apgList) {
		List<VerifyTaskAp> list = Lists.newArrayList();
		if (CollectionUtils.isEmpty(apgList)) {
			return list;
		}
		for (VerifyTaskApVO vo : apgList) {
			list.add(genVerifyTaskAp(task, vo));
		}
		return list;
	}

	private VerifyTaskAp genVerifyTaskAp(VerifyTask task, VerifyTaskApVO vo) {
		VerifyTaskAp apg = new VerifyTaskAp();
		BeanUtil.copyProperties(vo, apg);
		apg.setTaskCode(task.getTaskCode());
		apg.setLeName(task.getLeName());
		apg.setTsTrName(task.getTsTrName());
		apg.setSrcSpec(vo.getSpec());
		apg.setSpec(SpecificationUtil.parseNormalSpec(apg.getSrcSpec()));
		// apg.setAddedTime(LocalDateTime.now());
		// apg.setLastModifiedTime(LocalDateTime.now());
		return apg;
	}

	private List<VerifyTaskInvoice> genVerifyTaskInvoiceList(VerifyTask task, List<VerifyTaskInvoiceVO> invoiceList) {
		List<VerifyTaskInvoice> list = Lists.newArrayList();
		if (CollectionUtils.isEmpty(invoiceList)) {
			return list;
		}
		for (VerifyTaskInvoiceVO vo : invoiceList) {
			list.add(genVerifyTaskInvoice(task, vo));
		}
		return list;
	}

	private VerifyTaskInvoice genVerifyTaskInvoice(VerifyTask task, VerifyTaskInvoiceVO vo) {
		VerifyTaskInvoice invoice = new VerifyTaskInvoice();
		BeanUtil.copyProperties(vo, invoice);
		invoice.setTaskCode(task.getTaskCode());
		invoice.setLeName(task.getLeName());
		invoice.setTsTrName(task.getTsTrName());
		invoice.setSrcSpec(vo.getSpec());
		invoice.setSpec(SpecificationUtil.parseNormalSpec(invoice.getSrcSpec()));		
		// invoice.setAddedTime(LocalDateTime.now());
		// invoice.setLastModifiedTime(LocalDateTime.now());
		return invoice;
	}

	private VerifyTask genVerifyTask(String code, List<VerifyTaskInvoiceVO> invoiceList, List<VerifyTaskApVO> apgList) {
		VerifyTask task = new VerifyTask();
		task.setTaskCode(code);
		VerifyTaskInvoiceVO invoiceVO = invoiceList.get(0);
		task.setLeName(invoiceVO.getLeName());
		task.setTsTrName(invoiceVO.getTsTrName());
		task.setTaskDate(LocalDateTime.now());
		// task.setAddedTime(LocalDateTime.now());
		// task.setLastModifiedTime(LocalDateTime.now());
		return task;
	}

	@Override
	public void excuteVerifyTask(String taskCode) {
		// 1.加载待核销数据
		VerifyTask task = verifyTaskService.getByTaskCode(taskCode);
		Assert.notNull(task, String.format("根据%s查询不到核销任务", taskCode));
		Assert.isTrue(VerifyTaskStatusEnum.Ing.getCode() != task.getTaskStatus(),
				String.format("核销任务%s正在执行中", taskCode));
		List<VerifyTaskInvoice> invoiceList = taskInvoiceService.listUnmatchedByTaskCode(taskCode);
		List<VerifyTaskAp> apgList = taskApService.listUnmatchedByTaskCode(taskCode);
		if (CollectionUtils.isEmpty(invoiceList) || CollectionUtils.isEmpty(apgList)) {
			log.warn("未找到待匹配的核销任务{}明细数据", taskCode);
			return;
		}
		Collections.sort(invoiceList, Comparator.comparing(VerifyTaskInvoice::getInvoiceCode)
				.thenComparing(VerifyTaskInvoice::getInvoiceNo).thenComparing(VerifyTaskInvoice::getInvoiceSn));
		Collections.sort(apgList,
				Comparator.comparing(VerifyTaskAp::getPoCode).thenComparing(VerifyTaskAp::getPoItemId));
		log.info("发票核销-开始匹配,核销任务{},发票数量{},台账数量{}", taskCode, invoiceList.size(), apgList.size());
		// 2.开始核销任务
		verifyTaskService.startTask(task);

		// 3.执行核销，生成核销结果
		Map<SpecWithPrice, List<VerifyTaskAp>> apMap = SpecWithPriceHelper.groupingApWithinTolerance(apgList,
				priceTolerance);
		Map<SpecWithPrice, List<VerifyTaskInvoice>> invoiceMap = SpecWithPriceHelper
				.groupingInvoiceWithinTolerance(invoiceList, priceTolerance);
		for (Entry<SpecWithPrice, List<VerifyTaskAp>> apEntry : apMap.entrySet()) {
			SpecWithPrice apDim = apEntry.getKey();
			for (Iterator<Entry<SpecWithPrice, List<VerifyTaskInvoice>>> iter = invoiceMap.entrySet().iterator(); iter
					.hasNext();) {
				Entry<SpecWithPrice, List<VerifyTaskInvoice>> invoiceEntry = (Entry<SpecWithPrice, List<VerifyTaskInvoice>>) iter
						.next();
				SpecWithPrice invoiceDim = invoiceEntry.getKey();
				if (SpecWithPriceHelper.equalsWithinTolerance(apDim, invoiceDim, priceTolerance)) {
					log.info("发票核销-相同维度匹配,发票{},台账{}", JSONUtil.toJsonStr(invoiceDim), JSONUtil.toJsonStr(apDim));
					// 发票和台账匹配，并保存匹配结果
					matchBiz.match(invoiceDim, task, apEntry.getValue(), invoiceEntry.getValue());
					iter.remove();
					break;
				}
			}
		}

		// 4.结束核销任务
		verifyTaskService.endTask(task);
		log.info("发票核销-结束匹配");
	}

}
